package nextee.cabletest.controller;

import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import com.orsoncharts.Chart3D;
import com.orsoncharts.Chart3DFactory;
import com.orsoncharts.data.xyz.XYZSeries;
import com.orsoncharts.data.xyz.XYZSeriesCollection;
import com.orsoncharts.fx.Chart3DViewer;
import com.orsoncharts.graphics3d.ViewPoint3D;
import com.orsoncharts.plot.XYZPlot;
import gnu.io.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import net.sf.jxls.exception.ParsePropertyException;
import net.sf.jxls.transformer.XLSTransformer;
import nextee.cabletest.MainApp;
import nextee.cabletest.common.ChartName;
import nextee.cabletest.common.NexteeResourceBundle;
import nextee.cabletest.db.CableData;
import nextee.cabletest.protocol.ProtocolData;
import nextee.cabletest.protocol.ProtocolHandle;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;

import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created by ycj on 2015/3/24.
 */
public class MainController implements Initializable, ProtocolHandle.ProtocolCallback, MainApp.AppCloseEventListener{

    private SerialPort sp;
    private ConnectionSource conn;

    public Dao<CableData, Integer> getCableDataDao() {
        return cableDataDao;
    }

    private Dao<CableData, Integer> cableDataDao;
    private ProtocolHandle protocolHandle = new ProtocolHandle();
    private RealDataController realDataController;

    @FXML private Button read_db;
    @FXML private Button print_xls;
    @FXML private Button comport;
    @FXML private ListView chartlist;
    @FXML private ListView group_a_list;
    @FXML private ListView group_b_list;
    @FXML private ListView group_c_list;
    @FXML private ListView group_d_list;
    @FXML private ListView group_e_list;
    @FXML private BorderPane bp;
    @FXML private BorderPane mainframe;
    @FXML private TabPane chart_type;

    @FXML private ToggleGroup main_menu;
    @FXML private ToggleButton item_realtime;

    @FXML private Node history_ui;

    @FXML
    public void doExceptDataAction(ActionEvent event) {
        try{
            NexteeResourceBundle bundle = new NexteeResourceBundle();
            bundle.setObject(this);
            Node root = FXMLLoader.load(getClass().getResource("/except_data.fxml"), bundle);
            if(mainframe.getCenter().getId().equals("history_data")) {
                history_ui = mainframe.getCenter();
            }

            mainframe.setCenter(root);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    @FXML
    public void doHistoryDataAction(ActionEvent event) {
        if(history_ui!=null){
            mainframe.setCenter(history_ui);
        }
    }

    @FXML
    private void doRealDataAction(ActionEvent event){
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/real_data.fxml"), null);
            Node root = fxmlLoader.load();

            realDataController = (RealDataController)fxmlLoader.getController();
            //TODO: main controller call sub controller example
//            ProtocolData protocolData = new ProtocolData();
//            protocolData.voltage=13; protocolData.current=4; protocolData.channel=0; protocolData.position=8;
//            realDataController.setCurrentData(protocolData);

            if(mainframe.getCenter().getId().equals("history_data")) {
                history_ui = mainframe.getCenter();
            }

            mainframe.setCenter(root);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void initComport(){
        CommPortIdentifier main_cp=null;
        Enumeration portList = CommPortIdentifier.getPortIdentifiers();

        System.out.println("-------可用串口--------");
        while(portList.hasMoreElements()){
            CommPortIdentifier cp = (CommPortIdentifier)portList.nextElement();
            if(cp.getPortType()==CommPortIdentifier.PORT_SERIAL){
                System.out.println(cp.getName());
                if(cp.getName().equals(MainApp.readConf("port", "COM1"))){
                    main_cp = cp;
                }
            }
        }
        System.out.println("-----------------------");

        try {
            sp = (SerialPort) main_cp.open("SerialPort", 2000);
            sp.setSerialPortParams(38400, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
            sp.addEventListener(new SerialPortEventListener() {
                private byte[] recv_buf = new byte[1024];

                @Override
                public void serialEvent(SerialPortEvent spe) {
                    switch (spe.getEventType()) {
                        case SerialPortEvent.DATA_AVAILABLE:
                            SerialPort in = (SerialPort) spe.getSource();
                        {
                            try {
                                int recv_len = in.getInputStream().read(recv_buf);
                                protocolHandle.push(recv_buf, recv_len);
                                String s = new String(recv_buf, 0, recv_len, "gbk");
                                System.out.println(s);
                            } catch (IOException ex) {
                                Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                        break;
                    }
                }

            });
            sp.notifyOnDataAvailable(true);
            sp.getOutputStream().write("Hytera".getBytes());
        } catch (PortInUseException
                | UnsupportedCommOperationException
                | TooManyListenersException
                | IOException
                | NullPointerException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @FXML
    private void handleButtonAction(ActionEvent event){
        Button btn = (Button)event.getSource();

        if(btn.getId().equals("print_xls")){
            System.out.println("print");
            //List rows = db.queryForList("select rowid, * from sample_data");
            Map beans = new HashMap();
            //beans.put("list", rows);
            XLSTransformer transformer = new XLSTransformer();
            try {
                transformer.transformXLS("print.xls", beans, "output.xls");
            } catch (ParsePropertyException ex) {
                Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvalidFormatException ex) {
                Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void initDB(){
        try {
            conn = new JdbcConnectionSource("jdbc:sqlite:cable.db");
            TableUtils.createTableIfNotExists(conn, CableData.class);
            cableDataDao = DaoManager.createDao(conn, CableData.class);
        } catch (SQLException e) {
            e.printStackTrace();
        }
//        DriverManagerDataSource ds = new DriverManagerDataSource();
//        ds.setDriverClassName("org.sqlite.JDBC");
//        ds.setUrl("jdbc:sqlite:sample.db");
//        db = new JdbcTemplate(ds);
//
//        List rows = db.queryForList("select rowid, * from sample_data");
//        Iterator ite = rows.iterator();
//        while(ite.hasNext()){
//            Map row = (Map)ite.next();
//            System.out.println(String.format("%d, %s", row.get("rowid"), row.get("recv_time")));
//        }
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        initDB();

        protocolHandle.setCallback(this);
        initComport();

        ArrayList<Integer> device_data = new ArrayList<>();
        for(int i=0; i<10; i++){
            device_data.add(i+1);
        }
        group_a_list.setItems(FXCollections.observableList(device_data));
        group_b_list.setItems(FXCollections.observableList(device_data));
        group_c_list.setItems(FXCollections.observableList(device_data));
        group_d_list.setItems(FXCollections.observableList(device_data));
        group_e_list.setItems(FXCollections.observableList(device_data));

        chart_type.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
            @Override
            public void changed(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) {
                Tab selected = (Tab)newValue;

                Node root=null;
                String fxml_name = null;
                switch(selected.getText()){
                    case ChartName.STABLE_CHART:
                        root = createStabilityChart();
                        break;
                    case ChartName.PERFORM_CHART:
                        root = createPerformanceChart();
                        break;
                    case ChartName.RESPONSE_CHART:
                        root = createResponseChart();
                        break;
                    case ChartName.TREND_CHART:
                        root = createTrendChart();
                        break;
                }

                if(root != null) {
                    bp.setCenter(root);
                }
                else{
                    System.out.println("root is null");
                }
            }
        });

        bp.setCenter(createStabilityChart());

        main_menu.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
            @Override
            public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {
                ToggleButton toggle = (ToggleButton)newValue;
                switch(toggle.getId()){
                    case "item_realtime":
                        doRealDataAction(null);
                        break;
                    case "item_history":
                        doHistoryDataAction(null);
                        break;
                    case "item_except":
                        doExceptDataAction(null);
                        break;
                }
            }
        });

        main_menu.selectToggle(item_realtime);
    }

    public Node stability_chart;
    public Node performance_chart;
    public Node response_chart;
    public Node trend_chart;

    public Node createStabilityChart(){
        if(stability_chart==null) {
            NumberAxis xAxis = new NumberAxis("时间(天)", 0, 300, 30);
            NumberAxis yAxis = new NumberAxis("电阻(欧姆)", 0, 160, 20);
            stability_chart = new LineChart<Number, Number>(xAxis, yAxis);
        }

        return stability_chart;
    }

    public Node createPerformanceChart(){
        if(performance_chart==null) {
            NumberAxis xAxis = new NumberAxis("温度(摄氏度)", -40, 280, 40);
            NumberAxis yAxis = new NumberAxis("电阻(欧姆)", 0, 160, 20);
            performance_chart = new LineChart<Number, Number>(xAxis, yAxis);
        }
        return performance_chart;
    }

    public Node createResponseChart(){
        if(response_chart==null) {
            NumberAxis xAxis = new NumberAxis("时间(秒)", 0, 16, 2);
            NumberAxis yAxis = new NumberAxis("电阻(欧姆)", 0, 160, 20);
            response_chart = new LineChart<Number, Number>(xAxis, yAxis);
        }
        return response_chart;
    }

    public Node createTrendChart(){
        if(trend_chart==null) {
            XYZSeriesCollection ds = new XYZSeriesCollection();
            XYZSeries s1 = new XYZSeries("C4");
            for (int i = 0; i < 1440; i++) {
                s1.add(i, 2 * i, 3 * i);
            }
            ds.add(s1);
            Chart3D chart = Chart3DFactory.createScatterChart(null, null, ds, "时间", "电阻", "温度");
            chart.setViewPoint(ViewPoint3D.createAboveRightViewPoint(40));
            XYZPlot plot = (XYZPlot) chart.getPlot();
            plot.getZAxis().setRange(0, 400);
            plot.getXAxis().setRange(0, 500);
            plot.getYAxis().setRange(0, 200);
            chart.setAntiAlias(true);
            trend_chart = new Chart3DViewer(chart);
        }
        return trend_chart;
    }


    @Override
    public void handleProtocolData(byte[] raw_data) {
        ProtocolData proto_data = new ProtocolData(raw_data);
        CableData cableData = new CableData();
        cableData.setCableData(proto_data);
        try {
            cableDataDao.create(cableData);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        realDataController.setCurrentData(proto_data);
    }

    @Override
    public void handleAppCloseEvent() {
        if(sp!=null){
            sp.close();
        }

        try {
            conn.close();
        } catch (SQLException e) {
            //e.printStackTrace();
        }
    }
}
